#include "IntroState.h"
#include "Screen.h"
#include <cassert>
#include <sstream>
#include <SDL_opengl.h>
#include <SDL_opengl.h>
#include "Game.h"
#include "EventPoller.h"

static void TW_CALL Start(void *clientData)
{  
    TheMainRenderState::Instance()->SetData(TheIntroState::Instance()->GetData());
    TheGame::Instance()->RequestChange(TheMainRenderState::Instance());
}
static void TW_CALL Quit(void *clientData)
{  
    TheGame::Instance()->Quit();
}
IntroState::IntroState() : m_bar(NULL)
{
    m_screenX = 0;
    m_screenY = 0;
    m_data.numThreads = 2;
    m_shouldSplit = true;
    m_data.taskDivision = 1;
    m_numberOfRaysPP = 0;
    m_totalRays = 0;
    m_raysPerTask = 0;
    m_raysPerThread  = 0;
}
void IntroState::Update()
{
    if(m_shouldSplit)
        m_data.taskSplit = 0;
    else
        m_data.taskSplit = 1;

    m_numberOfRaysPP = m_data.numLights + m_data.recursion;
    m_totalRays = m_numberOfRaysPP * 512 * 512;
    if(m_data.taskSplit == 0)
    {
        int totalTasks = (int)powf(2.0f,(float)(m_data.taskDivision+1));
        m_raysPerTask = m_totalRays / totalTasks;
        int totalThreads = totalTasks; //some threads may not work as tehre are not enough tasks
        if(m_data.numThreads < totalTasks)
            totalThreads = m_data.numThreads;
        m_raysPerThread = m_raysPerTask*(totalTasks /totalThreads);
    }
    else
    {
        m_raysPerTask = 0;
        m_raysPerThread = m_totalRays;
    }
}
void IntroState::Draw()
{
    //Clear the active buffers
    glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);

    ManageTileModeUI();
    ManageSceneSelectionUI();
    ManageTaskDivisionsUI();


    TestTw(TwDraw());
}
void IntroState::Initialise()
{
#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} Initialising()..." << std::endl;
#endif

    TheEventPoller::Instance()->AddHandler(this);
    m_screenX = TheScreen::Instance()->GetWidth();
    m_screenY = TheScreen::Instance()->GetHeight();
    if(m_bar == NULL)
    {
        m_bar = TwNewBar("MainMenu");
    }
    else
    {
        m_bar = TwGetBarByName("MainMenu");
        TwRemoveAllVars(m_bar);
    }
    if(m_bar == NULL)
        assert(0);
     TwDefine("MainMenu visible=true");
    CreateUI();

#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} Initialised Succesfully : " << std::endl;
#endif
}
void IntroState::CleanUp()
{
#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} Calling CleanUp()..." << std::endl;
#endif


    TwDefine("MainMenu visible=false");
    TheEventPoller::Instance()->RemoveHandler(this);


#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} CleanUp sucesfull" << std::endl;
#endif
}
void IntroState::OnResume()
{
#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} Resuming..." << std::endl;
#endif


    m_bar = TwGetBarByName("MainMenu");
    TwRemoveAllVars(m_bar);
    if(m_bar == 0)
        assert(0);
    TwDefine("MainMenu visible=true");
    CreateUI();
    TheEventPoller::Instance()->AddHandler(this);

#ifdef DEBUGGING
    std::cout << "{IntroState Singleton} Resumed Succesfully..." << std::endl;
#endif
}
void IntroState::CreateUI()
{
    TestTw(TwDefine("MainMenu color='255 255 255' alpha=0 "));    
    TestTw(TwDefine("MainMenu position = '0 0'"));
    TestTw(TwDefine("MainMenu iconifiable=false"));
    TestTw(TwDefine("MainMenu movable=false"));
    TestTw(TwDefine("MainMenu resizable=false"));
    TestTw(TwDefine("MainMenu fontresizable=false"));
    //SIZE
    std::string size = "MainMenu size = '";
    std::stringstream sizeSS;
    sizeSS << m_screenX << " " << m_screenY <<"' ";
    size +=sizeSS.str();
    TestTw(TwDefine(size.c_str()));
    //data
    TestTw(TwAddVarRO(m_bar, "Number of RaysPP",TW_TYPE_INT32, &m_numberOfRaysPP,
        "label='Number of rays per pixel'"));
    TestTw(TwAddVarRO(m_bar, "Number of RaysPF",TW_TYPE_INT32, &m_totalRays,
        "label='Number of rays per frame'"));
    TestTw(TwAddVarRO(m_bar, "Number of RaysPT",TW_TYPE_INT32, &m_raysPerTask,
        "label='Number of rays per task'"));
    TestTw(TwAddVarRO(m_bar, "Number of RaysPThread",TW_TYPE_INT32, &m_raysPerThread,
        "label='Number of rays per thread'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    // num threads
    TestTw(TwAddVarRW(m_bar, "Number of Threads",TW_TYPE_INT32, &m_data.numThreads,
        "label='Number of threads to use: '\
        min=1 max=8 step=1\
        help='Change the number of threads' "));
    //recursions
    TestTw(TwAddVarRW(m_bar, "Number of recursions",TW_TYPE_INT32, &m_data.recursion,
        "label='Number of Recursions to use: '\
        min=1 max=9 step=2\
        help='Change the maximum number of recursions' "));
    TestTw(TwAddButton(m_bar,"Recursive", NULL, NULL, "label = 'Effects the procedural scenes only, improves accuracy'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //tile render mode
    TestTw(TwAddVarRW(m_bar, "Color Keys",TW_TYPE_INT32, &m_data.tileMode,
        "label='How to colour key the scene: '\
        min=0 max=2 step=1\
        help='Change the color ovberlay ' "));
    TestTw(TwAddButton(m_bar,"Key", NULL, NULL, "label = '0: no color overlay'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //scene selction
    TestTw(TwAddVarRW(m_bar, "Scene Selection",TW_TYPE_INT32, &m_data.whichBuild,
        "label='Scene: '\
        min=0 max=3 step=1\
        help='Change the scene' "));
    TestTw(TwAddButton(m_bar,"Scene", NULL, NULL, "label = '0: Simplest procedurally generated scene'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //smooth shading
    TestTw(TwAddVarRW(m_bar, "Smooth Shading ",TW_TYPE_BOOLCPP, &m_data.smoothShading,
        "label='Smooth Shading mode: '\
        help='Turns smooth shading on or off' "));
    TestTw(TwAddButton(m_bar,"Shading", NULL, NULL, "label = 'When using meshes, smooth the normals'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //num lights, poins lights
    TestTw(TwAddVarRW(m_bar, "Num Lights",TW_TYPE_INT32, &m_data.numLights,
        "label='Number of Lights: '\
        min=1 max=4 step=1\
        help='Change the number of lights in the scene' "));
    TestTw(TwAddVarRW(m_bar, "Light Type",TW_TYPE_BOOLCPP, &m_data.pointLights,
        "label='Make the lights point lights? (slower)'\
        help='Make the lights into point or directional lights' "));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //To tile or not
    TestTw(TwAddVarRW(m_bar, "Split Tasks",TW_TYPE_BOOLCPP, &m_shouldSplit,
        "label='Split the tasks: '\
        help='Split the tasks into smaller ones' "));
    TestTw(TwAddButton(m_bar,"Tasks", NULL, NULL, "label = 'Recursively split the screen into smaller tasks'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //tiling style
    TestTw(TwAddVarRW(m_bar, "Task Division",TW_TYPE_INT32, &m_data.taskDivision,
        "label='Task Division: '\
        min=0 max=7 step=1\
        help='How many times to split the tasks up' "));
    TestTw(TwAddButton(m_bar,"Division", NULL, NULL, "label = '0: One task for the whole scene'"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    // buttons
    TestTw(TwAddButton(m_bar, "Start Ray Tracing!", (TwButtonCallback)&Start, this, "help = 'Starts the Demo'"));
    //
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    TestTw(TwAddButton(m_bar, "Quit", (TwButtonCallback)&Quit, this, "help = 'Quits the Demo'"));
    //
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
}
void IntroState::ManageTileModeUI()
{
    switch(m_data.tileMode)
    {
    case 0 :
        {
            TestTw(TwDefine("MainMenu/Key label = '0: no color overlay'"));
            break;
        }
    case 1 :
        {
            TestTw(TwDefine("MainMenu/Key label = '1: Each thread has its own colour key'"));
            break;
        }
    case 2 :
        {
            TestTw(TwDefine("MainMenu/Key label = '2: Tasks are colored independently to show the separation'"));
            break;
        }
    }
}
void IntroState::ManageSceneSelectionUI()
{
    switch(m_data.whichBuild)
    {
    case 0 : 
        {
            TwDefine("MainMenu/Scene label = '0: Simplest procedurally generated scene'");
            break;
        }
    case 1 : 
        {
            TwDefine("MainMenu/Scene label = '1: A more complex procedurally generated scene'");
            break;
        }
    case 2 : 
        {
            TwDefine("MainMenu/Scene label = '2: A simple mesh '");
            break;
        }
    case 3 : 
        {
            TwDefine("MainMenu/Scene label = '3: A large complicated group of meshes (long load time!)'");
            break;
        }
    }
}
void IntroState::ManageTaskDivisionsUI()
{
    switch(m_data.taskDivision)
    {
    case 0 :
        {
            TwDefine("MainMenu/Division label = '0: One task for the whole scene'");
            break;
        }
    case 1 :
        {
            TwDefine("MainMenu/Division label = '1: One division, splits the screen into 4 tasks'");
            break;
        }
    case 2 :
        {
            TwDefine("MainMenu/Division label = '2: Two divisions, splits the screen into 16 tasks'");
            break;
        }
    case 3 :
        {
            TwDefine("MainMenu/Division label = '3: Three divisions, splits the screen into 64 tasks'");
            break;
        }
    case 4 :
        {
            TwDefine("MainMenu/Division label = '4: Four divisions, splits the screen into 256 tasks'");
            break;
        }
    case 5 :
        {
            TwDefine("MainMenu/Division label = '5: Five divisions, splits the screen into 1024 tasks'");
            break;
        }
    case 6 :
        {
            TwDefine("MainMenu/Division label = '6: Six divisions, splits the screen into 4096 tasks'");
            break;
        }
    case 7 :
        {
            TwDefine("MainMenu/Division label = '7: Seven divisions, splits the screen into 16384 tasks'");
            break;
        }
    }
}

